//
// @Author: Zhenwei Xiao
// @Description:
// @Version: 1.0.0
// @Date: 2021/4/6 下午4:16
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//

const its = require('./ITransport')
const LpPacket = require('../packet/LpPacket')
const encoding = require('../encoding/Encoder')
const block = require('../encoding/Block')
const MINPacket = require('../packet/MINPacket')
// const lf = require("./Logicface")

class LinkService {
    constructor() {
        this.transport = null
        this.logicFace = null
        this.mtu = 0
        this.lpPacketHeadSize = 0
        this.lpPacketId = 0
        // transport ITransport // 传输通道
        // logicFace *LogicFace // LinkService关联的logicFace
        // lpReassemble LpReassemble // 包分片合并器

        // mtu              int    // MTU大小
        // lpPacketHeadSize int    // lpPacket 编码成数组时的头部大小
        // lpPacketId       uint64 // 发送的lpPacket 编码
    }

    //
    // @Description: 	计算lpPacket头部大小
    // @receiver l
    //
    calculateLpPacketHeadSize() {
        var lpPacket = new LpPacket()
        lpPacket.LpPacketHeader.LpPacketFragmentId.setId(9223372036854775807)
        lpPacket.LpPacketHeader.LpPacketFragmentSeq.setFragmentSeq(9223372036854775807)
        lpPacket.LpPacketHeader.LpPacketFragmentNum.setFragmentNum(9223372036854775807)
        // Q?
        var buf = new Buffer.alloc(encoding.MaxPacketSize)
        lpPacket.Payload.setValue(buf.buffer)
        var encoder = new encoding.Encoder
        try{
            encoder.encoderReset(encoding.MaxPacketSize+1000, 0)
        }catch (err){
            throw new Error("cannot calculate lpPacketHeadSize in LinkService init " + err)
        }
        try {
            this.lpPacketHeadSize = lpPacket.wireEncode(encoder)
            this.lpPacketHeadSize = this.lpPacketHeadSize - encoding.MaxPacketSize
        }catch (err){
            throw new Error("cannot calculate lpPacketHeadSize in LinkService init" + err)
        }
    }

    //
    // @Description: 初始化linkService
    // @receiver l
    // @param mtu int MTU，最大传输单元
    //
    Init(mtu) {
        this.mtu = mtu
        //l.lpReassemble.Init()
        this.calculateLpPacketHeadSize()
        this.lpPacketId = 0
    }

    //
    // @Description: 从lpPacket中提取出MINPacket对象
    // @receiver l
    // @param lpPacket  *packet.LpPacket 对象指针
    // @return *packet.MINPacket	MINPacket对象指针
    // @return error	提取失败错误信息
    //
    getMINPacketFromLpPacket(lpPacket) {
        // lpPacket是数组
        var payload = lpPacket.Payload.getValue()
        var blocks
        try {
            blocks = block.createBlockByBuffer(payload, true)
        }catch (err){
            return err
        }
        var minPacket = new MINPacket
        try{
            minPacket.wireDecode(blocks)
        }catch (err){
            return err
        }
        return minPacket
    }

    //
    // @Description: 	收到lpPacket包的处理函数，该函数被相关联的 transport 的 receive 函数调用
    // @receiver l
    // @param lpPacket 	lpPacket对象指针
    // @return *packet.MINPacket, error
    //
    ReceivePacket() {
        var lpPacket
        try {
            console.log("this.transport",this.transport)
            lpPacket = this.transport.Receive()
            if (lpPacket[1] != null){
                throw lpPacket[1]
            }
        }catch (err){
            throw err
        }
        // console.log(lpPacket)
        // 未分包，只有一个包
        var minPacket
        try {
            minPacket = this.getMINPacketFromLpPacket(lpPacket[0])
        }catch (err){
            throw err
        }
        return minPacket
    }

    //
    // @Description: 发送一个lp包分片
    // @receiver l
    // @param buf []byte	        分片的数据
    // @param bufLen int	        数据长度
    // @param fragmentId uint64	    分片号
    // @param fragmentNum uint64	分片数
    // @param fragmentSeq uint64	第几块分片，从0开始
    //
    sendFragment(buf, bufLen, fragmentId, fragmentNum, fragmentSeq) {
        var lpPacket = new LpPacket()
        lpPacket.LpPacketHeader.LpPacketFragmentId.setId(fragmentId)
        lpPacket.LpPacketHeader.LpPacketFragmentNum.setFragmentNum(fragmentNum)
        lpPacket.LpPacketHeader.LpPacketFragmentSeq.setFragmentSeq(fragmentSeq)
        lpPacket.Payload.setValue(buf.slice(0,bufLen))
        console.log("fragment :" , lpPacket)
        console.log("transport1111111:", this.transport)
        return this.transport.Send(lpPacket)
    }

    //
    // @Description: 发送指定长度的一段数据，如果数据过长，会调用sendFragment发送多个分片
    // @receiver l
    // @param buf []byte 要发送的数据指针
    // @param bufLen int 数据长度
    // @return error
    //
    sendByteBuffer(buf, bufLen) {
        var fragmentLen = this.mtu - this.lpPacketHeadSize
        var startIdx = 0
        var fragmentSeq = 0
        var fragmentNum = parseInt(bufLen / fragmentLen)
        if (bufLen%fragmentLen != 0) {
            fragmentNum++
        }
        console.log(fragmentLen, fragmentSeq, fragmentNum)
        while (startIdx < bufLen) {
            if (fragmentLen > bufLen-startIdx) {
                fragmentLen = bufLen - startIdx
            }
            console.log(buf.slice(startIdx,startIdx+fragmentLen), fragmentLen, this.lpPacketId, BigInt(fragmentNum),
                BigInt(fragmentSeq))
            var err = this.sendFragment(buf.slice(startIdx,startIdx+fragmentLen), fragmentLen, this.lpPacketId, BigInt(fragmentNum),
                BigInt(fragmentSeq))
            if (err != null) {
                return err
            }
            startIdx += fragmentLen
            fragmentSeq++
        }
        this.lpPacketId++
        return null
    }

    //
    // @Description: 	发送一个兴趣包
    // @receiver l
    // @param interest	*packet.Interest 兴趣包对象指针
    // @return error
    //
    SendInterest(interest) {
        var encoder = new encoding.Encoder
        try{
            encoder.encoderReset(encoding.MaxPacketSize, 0)
        }catch (err){
            return err
        }
        var bufLen
        try{
            bufLen= interest.wireEncode(encoder)
        }catch (err){
            return err
        }
        var buf
        try {
            buf = encoder.getBuffer()
        }catch (err){
            return err
        }
        console.log("buf:", buf,"\nbufLen:",bufLen)
        return this.sendByteBuffer(buf, bufLen)
    }

    //
    // @Description:  发送一个数据包
    // @receiver l
    // @param data *packet.Data数据包对象指针
    //
    SendData(data) {
        var encoder = new encoding.Encoder
        try{
            encoder.encoderReset(encoding.MaxPacketSize, 0)
        }catch (err){
            return err
        }
        var bufLen
        try {
            bufLen = data.wireEncode(encoder)
        }catch (err){
            return err
        }
        var buf
        try {
            buf = encoder.getBuffer()
        }catch (err){
            return err
        }
        return this.sendByteBuffer(buf, bufLen)
    }

    //
    // @Description: 	发送一个普通推送式网络包
    // @receiver l
    // @param cPacket *packet.CPacket
    //
    SendCPacket(cPacket) {
        var encoder = new encoding.Encoder
        try{
            encoder.encoderReset(encoding.MaxPacketSize, 0)
        }catch (err){
            return err
        }
        var bufLen
        try {
            bufLen = cPacket.wireEncode(encoder)
        }catch (err){
            return err
        }
        var buf
        try {
            buf = encoder.getBuffer()
        }catch (err){
            return err
        }
        return this.sendByteBuffer(buf, bufLen)
    }

    //
    // @Description: 	发送一个网络包
    // @receiver l
    // @param minPacket *packet.MINPacket
    //
    SendMINPacket(minPacket) {
        var encoder = new encoding.Encoder
        try{
            encoder.encoderReset(encoding.MaxPacketSize, 0)
        }catch (err){
            return err
        }
        var bufLen
        try {
            bufLen = minPacket.wireEncode(encoder)
        }catch (err){
            return err
        }
        var buf
        try {
            buf = encoder.getBuffer()
        }catch (err){
            return err
        }
        return this.sendByteBuffer(buf, bufLen)
    }
}

module.exports = {
    LinkService: LinkService
}